package com.zsl.swing.redis.desktop.window.tree;

import com.zsl.swing.redis.desktop.model.FontSizeConfigEntity;
import com.zsl.swing.redis.desktop.model.NodeEntity;
import com.zsl.swing.redis.desktop.type.DbOptEnum;
import com.zsl.swing.redis.desktop.type.MainMenuEnum;
import com.zsl.swing.redis.desktop.type.NodeTypeEnum;
import com.zsl.swing.redis.desktop.utils.*;
import com.zsl.swing.redis.desktop.window.ZslRedisDesktopMainWindow;
import com.zsl.swing.redis.desktop.window.cmd.ZslRedisCmdWindows;
import com.zsl.swing.redis.desktop.window.menu.ZslMenuItem;
import com.zsl.swing.redis.desktop.window.panel.ZslConnectionPanel;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;
import java.util.List;

public class ZslServerTree{

    private static JTree me;

    /**
     * 根节点
     */
    private ZslServerTree(){
    }

    public static JTree getTree(){
        return buildTree();
    }

    private static JTree buildTree(){
        DefaultMutableTreeNode rootNode = NodeEntity.getServerTreeRootNode();
        JTree tree = new JTree(rootNode);
        List<NodeEntity> serverNodeEntityList = ConfigUtils.readConnections();

        RedisUtils.addConnections(serverNodeEntityList);
        serverNodeEntityList.stream().map(DefaultMutableTreeNode::new).forEach(rootNode::add);

        tree.setCellRenderer(new ConnectionTreeCellRender());
        tree.addMouseListener(new TreeMouseClickAction());
        tree.expandPath(new TreePath(rootNode));
        tree.setVisible(true);

        FontSizeConfigEntity fontSizeConfig = ZslRedisDesktopMainWindow.getFontSizeConfig();
        tree.setFont(FontUtils.getFont(fontSizeConfig.getFontName(), Font.PLAIN, fontSizeConfig.getTree()));

        me = tree;
        return tree;
    }

    public static NodeEntity getSelectedEntity(){
        TreePath path = me.getSelectionPath();
        if(Objects.isNull(path)){
            return null;
        }
        DefaultMutableTreeNode selectNode = (DefaultMutableTreeNode) path.getLastPathComponent();
        return (NodeEntity)selectNode.getUserObject();

    }

    public static void refreshTree(){
        List<NodeEntity> nodeEntities = ConfigUtils.readConnections();

        DefaultMutableTreeNode rootNode = NodeEntity.getServerTreeRootNode();
        rootNode.removeAllChildren();

        nodeEntities.stream().map(DefaultMutableTreeNode::new).forEach(rootNode::add);


        me.clearSelection();
        me.expandPath(new TreePath(rootNode));
        me.updateUI();
    }

    public static void saveNode(NodeEntity entity) {
        boolean result = ConfigUtils.saveConnection(entity);
        if(result){
            RedisUtils.putConnectionMap(entity);
            refreshTree();
            DialogUtils.msgDialog(ZslRedisDesktopMainWindow.getMainWindow(),"保存成功！");
        } else{
            ZslRedisDesktopMainWindow.getZslLogPanel().logError("保存连接失败");
            DialogUtils.errorDialog(ZslRedisDesktopMainWindow.getMainWindow(),"保存连接失败！");
        }
    }

    public static void deleteNode(NodeEntity entity) {
        boolean result = ConfigUtils.deleteConnection(entity);
        if(result){
            refreshTree();
            RedisUtils.removeConnection(entity.getUniqueId());
            DialogUtils.msgDialog(ZslRedisDesktopMainWindow.getMainWindow(),"删除成功！");
        }else{
            ZslRedisDesktopMainWindow.getZslLogPanel().logError("删除连接失败");
            DialogUtils.errorDialog("删除连接失败！");
        }

    }


    private static class ConnectionTreeCellRender extends DefaultTreeCellRenderer {
        private static final long serialVersionUID = 1L;


        public ConnectionTreeCellRender() {
            super();
        }

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
                                                      boolean leaf, int row, boolean hasFocus) {
            super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);

            DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
            NodeEntity nodeEntity = (NodeEntity) node.getUserObject();
            setText(nodeEntity.getShowName());
            setIcon(nodeEntity.getNodeType().getIcon());
            return this;
        }
    }

    private static class TreeMouseClickAction extends MouseAdapter implements ActionListener {


        @Override
        public void mousePressed(MouseEvent e) {
            TreePath path = me.getPathForLocation(e.getX(), e.getY());
            if(path == null) {
                return;
            }

            DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
            NodeEntity entity = (NodeEntity)node.getUserObject();

            if(!entity.isRoot()) {
                me.setSelectionPath(path);
            }

            if(entity.isDb()){
                RedisUtils.selectDb(entity.getUniqueId(), entity.getDbIndex());
            }
        }

        @Override
        public void mouseClicked(MouseEvent e) {
            TreePath path = me.getPathForLocation(e.getX(), e.getY());
            if(path == null) {
                return;
            }

            DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
            NodeEntity entity = (NodeEntity)node.getUserObject();

            int type = e.getButton();
            if(type == MouseEvent.BUTTON3){
                //右键点击
                this.doWhenRightClick(entity,e);
            }else if(type == MouseEvent.BUTTON1){
                //左键点击
                this.doWhenLeftClick(node,entity,e);

            }
        }

        private void doWhenRightClick(NodeEntity entity, MouseEvent e){
            if(entity.isRoot()){
                JPopupMenu popupMenu = this.getServerMenu();
                popupMenu.show(me,e.getX(),e.getY());
            }else if(entity.isServer()){
                JPopupMenu popupMenu = this.getServerMenu();

                ZslMenuItem menuItem = ZslMenuItem.getInstance(DbOptEnum.OPEN_CONSOLE.getText(),event -> {
                    NodeEntity dbEntity = new NodeEntity();
                    dbEntity.setUniqueId(entity.getUniqueId());
                    dbEntity.setDbIndex(0);
                    dbEntity.setShowName(entity.getShowName());
                    dbEntity.setParent(entity);

                    ZslRedisCmdWindows.showCmdWindow(dbEntity);
                });
                popupMenu.add(menuItem);
                popupMenu.show(me,e.getX(),e.getY());
            }else if(entity.isDb()){
                ActionListener actionListener = this.buildActionListener(entity);
                ZslMenuItem c = ZslMenuItem.getInstance(DbOptEnum.NEW_WINDOW.getText(), actionListener);
                ZslMenuItem o = ZslMenuItem.getInstance(DbOptEnum.OPEN_CONSOLE.getText(), actionListener);
                ZslMenuItem f = ZslMenuItem.getInstance(DbOptEnum.FLUSH.getText(), actionListener);

                JPopupMenu popupMenu = new JPopupMenu();
                popupMenu.add(c);
                popupMenu.add(o);
                popupMenu.add(f);

                popupMenu.show(me,e.getX(),e.getY());
            }

        }

        private JPopupMenu getServerMenu(){
            ZslMenuItem c = ZslMenuItem.getInstance(MainMenuEnum.ADD.getText(), this);
            ZslMenuItem u = ZslMenuItem.getInstance(MainMenuEnum.UPDATE.getText(), this);
            ZslMenuItem r = ZslMenuItem.getInstance(MainMenuEnum.READ.getText(), this);
            ZslMenuItem d = ZslMenuItem.getInstance(MainMenuEnum.DELETE.getText(), this);

            JPopupMenu popupMenu = new JPopupMenu();
            popupMenu.add(c);
            popupMenu.add(u);
            popupMenu.add(r);
            popupMenu.add(d);

            return popupMenu;
        }

        private ActionListener buildActionListener(NodeEntity entity){
            return event -> {
                String actionCommand = event.getActionCommand();
                if(DbOptEnum.NEW_WINDOW.getText().equals(actionCommand)){
                    ZslRedisDesktopMainWindow.getZslShowPanel().addNewTabbedPane(entity);
                }else if(DbOptEnum.OPEN_CONSOLE.getText().equals(actionCommand)){
                    NodeEntity dbEntity = new NodeEntity();
                    dbEntity.setParent(entity.getParent());
                    dbEntity.setShowName(entity.getShowName());
                    dbEntity.setDbIndex(entity.getDbIndex());
                    dbEntity.setUniqueId(entity.getUniqueId());
                    ZslRedisCmdWindows.showCmdWindow(dbEntity);
                }else if(DbOptEnum.FLUSH.getText().equals(actionCommand)){
                    boolean result = DialogUtils.confirmDialog(ZslRedisDesktopMainWindow.getMainWindow(), "确定要清空数据？");
                    if(result){
                        long start = System.currentTimeMillis();
                        RedisUtils.flushDb(entity.getUniqueId(),entity.getDbIndex());
                        ZslRedisDesktopMainWindow.getZslLogPanel().log("界面执行[flush]命令耗时：" + (System.currentTimeMillis() - start) + "毫秒！");
                        DialogUtils.msgDialog(ZslRedisDesktopMainWindow.getMainWindow(), "清空数据成功！");
                    }
                }
            };
        }
        private void doWhenLeftClick(DefaultMutableTreeNode node, NodeEntity entity, MouseEvent e){
            int count = e.getClickCount();
            if(count == 2){
                //双击连接，展示数据库，
                if(entity.isDb()){
                    ZslRedisDesktopMainWindow.getZslShowPanel().addNewTabbedPane(entity);
                }else
                if(entity.isServer()){
                    ZslServerTree.createDbNodeList(node);
//                    Enumeration<TreeNode> children = node.children();
//                    if(!children.hasMoreElements()){
//                        ZslServerTree.createDbNodeList(node);
//                    }else{
//                        //更新key数量
//                        Map<String, String> keyCountMap = RedisUtils.infoKeyCount(entity);
//                        while(children.hasMoreElements()){
//                            DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) children.nextElement();
//                            NodeEntity userObject = (NodeEntity) treeNode.getUserObject();
//                            if(userObject.isDb()){
//                                String newName = userObject.getDbIndex() + "(" + keyCountMap.getOrDefault("db" + userObject.getDbIndex(), "0") + ")";
//                                userObject.setShowName(newName);
//                            }
//                        }
//                    }

                }
            }
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            ZslConnectionPanel.doActionForMenu(e.getActionCommand());
        }
    }

    private static void createDbNodeList(DefaultMutableTreeNode node) {
        node.removeAllChildren();
        NodeEntity entity = (NodeEntity)node.getUserObject();

        boolean result = RedisUtils.testConn(entity);

        if(!result){
            DialogUtils.errorDialog(ZslRedisDesktopMainWindow.getMainWindow(),"连接失败！");
            return;
        }

        Map<String, String> keyCountMap = RedisUtils.infoKeyCount(entity);
        int dbCount = ZslRedisDesktopMainWindow.getDbCountConfig().getDbCount();
        for(int i=0; i< dbCount; i++){
            NodeEntity dbEntity = new NodeEntity();
            dbEntity.setDbIndex(i);
            dbEntity.setNodeType(NodeTypeEnum.DB);
            dbEntity.setUniqueId(entity.getUniqueId());
            if(CollectionUtils.isEmpty(keyCountMap)){
                dbEntity.setShowName(String.valueOf(i));
            }else{
                String keyCount = keyCountMap.getOrDefault("db" + i, "0");
                dbEntity.setShowName(i + "(" + keyCount + ")");
            }

            dbEntity.setParent(entity);
            DefaultMutableTreeNode dbNode = new DefaultMutableTreeNode(dbEntity);
            node.add(dbNode);

        }

        me.expandPath(new TreePath(node.getPath()));
        me.updateUI();
    }
}
